

import Vector3 =Laya.Vector3;
import Quaternion =Laya.Quaternion;
import Ease = Laya.Ease;
import Camera = Laya.Camera;

class AICameraCtrl{
    private noTask=true;
    private _targetPos = new Vector3();
    private _targetRot = new Quaternion();
    private _targetFov = 60;
    private _startPos = 0;
    private _startRot = 0;
    private _durationPos = 1000;
    private _durationRot = 1000;
    private _updateFuncPos:(t:number)=>void=null;  //TODO 移动和旋转可以同时进行
    private _updateFuncRot:(t:number)=>void=null;  //TODO 移动和旋转可以同时进行
    private _viewSkySavePos=new Vector3();

    update(){
        let now = Date.now();
        if(this._startPos==0 && this._startRot==0){
            return;
        }


        if(this._startPos>0){
            let dtpos = now - this._startPos;
            let tpos = Ease.quartOut(dtpos,0,1,this._durationPos);
            this._updateFuncPos(tpos);
            if(tpos>0.999||tpos<=0){
                //完成了
                this._startPos=0;
            }
        }

        if(this._startRot>0){
            let dtrot = now - this._startRot;
            let trot = Ease.quartOut(dtrot,0,1,this._durationRot);
            this._updateFuncRot(trot);
            if(trot>0.999||trot<=0){
                this._startRot=0;
            }
        }

        if(this._startPos==0&&this._startRot==0){
            // 清理timer
            Laya.timer.clear(this,this.update);
            this.noTask=true;
        }
    }

    startPos(update:(t:number)=>void){
        this._updateFuncPos=update;
        this._startPos = Date.now();
        if(this.noTask){
            this.noTask=false;
            Laya.timer.loop(1,this,this.update);
        }
    }
    startRot(update:(t:number)=>void){
        this._updateFuncRot=update;
        this._startRot = Date.now();
        if(this.noTask){
            this.noTask=false;
            Laya.timer.loop(1,this,this.update);
        }
    }

    private _tmpV3 = new Vector3();
    private _lerpPos(start:Vector3, end:Vector3, t:number){
        let pos = this._tmpV3;
        pos.x = start.x + (end.x - start.x) * t;
        pos.y = start.y + (end.y - start.y) * t;
        pos.z = start.z + (end.z - start.z) * t;
        return pos;
    }

    private _tmpQ = new Quaternion();
    private _lerpRot(start:Quaternion, end:Quaternion, t:number){
        let rot = this._tmpQ;
        Quaternion.slerp(start,end,t,rot);
        return rot;
    }

    private _rotateY(cam:Camera, degree:number, target:Quaternion){
        let cq = cam.transform.rotation;
        Quaternion.createFromYawPitchRoll(degree,0,0,target);
        Quaternion.multiply(target,cq,target);
        return target;
    }

    private _rotateX(cam:Camera, degree:number, target:Quaternion){
        let cq = cam.transform.rotation;
        let wmat = cam.transform.worldMatrix;
        let right = new Vector3(wmat.elements[0],wmat.elements[1],wmat.elements[2]);
        right.normalize();
        Quaternion.createFromAxisAngle(right,degree,target);
        Quaternion.multiply(target,cq,target);
        return target;
    }

    /**
     * 转到某个角度。不是在当前基础上转
     * @param cam
     * @param degree
     * @param target
     * @returns
     */
    private _rotateToX(cam:Camera, degree:number, target:Quaternion){
        let wmat = cam.transform.worldMatrix;
        let right = new Vector3(wmat.elements[0],wmat.elements[1],wmat.elements[2]);
        right.normalize();
        Quaternion.createFromAxisAngle(right,degree,target);
        return target;
    }

    private _xUnitVec3 = new Vector3(1, 0, 0);
    private _yUnitVec3 = new Vector3(0, 1, 0);
    private _tmpVec3 = new Vector3();
    private rotationTo(out: Quaternion, a: Vector3, b: Vector3): boolean {
        var dot: number = Vector3.dot(a, b);
        if (dot < -0.999999) {// 180度了，可以选择多个轴旋转
            Vector3.cross(this._xUnitVec3, a, this._tmpVec3);
            if (Vector3.scalarLength(this._tmpVec3) < 0.000001)
                Vector3.cross(this._yUnitVec3, a, this._tmpVec3);
            Vector3.normalize(this._tmpVec3, this._tmpVec3);
            Quaternion.createFromAxisAngle(this._tmpVec3, Math.PI, out);
            return true
        } else if (dot > 0.999999) {// 没有变化
            out.x = 0;
            out.y = 0;
            out.z = 0;
            out.w = 1;
            return false;
        } else {
            // 下面是求这个四元数，这是一个简化求法，根据cos(a/2)=√((1+dot)/2), cos(a/2)sin(a/2)=sin(a)/2 就能推导出来
            Vector3.cross(a, b, this._tmpVec3);
            out.x = this._tmpVec3.x;
            out.y = this._tmpVec3.y;
            out.z = this._tmpVec3.z;
            out.w = 1 + dot;
            out.normalize(out);
            return true;
        }
        return false;
    }

    cmd(scene:IEditorEnv.IGameScene, operate:string, value:number|string){
        debugger;
        let editorCamera = (EditorEnv as any).d3Manager.sceneCamera;
        let camera = editorCamera._camera;
        let step = new Vector3();
        let dist = 10||(+value);
        let rotate = Math.PI/4||+value;
        let fovStep = 15;
        let forward:Vector3;
        //let curpos = camera.transform.position;
        let targetPos = this._targetPos;
        let targetRot = this._targetRot;
        let startPos = editorCamera.pivot.clone();// camera.transform.position.clone();
        let startQuat = camera.transform.rotation.clone();
        let startFov = camera.fieldOfView;
        let right:Vector3;
        let up:Vector3;
        let d=0;

        switch (operate) {
            case "foward":   case "前进":
                forward = editorCamera.normalizedForward;
                //forward.scale(-1, forward); //方向是反的
                d = (value as number)||dist;
                forward.scale(d,step);
                startPos.vadd(step,targetPos);

                this.startPos((t:number)=>{
                    //直接设置摄像机会被editorCamera冲掉，所以设置editorCamer
                    editorCamera.pivot = this._lerpPos(startPos,targetPos,t);
                    editorCamera.SetupCamera();//这个才导致起效
                });
                break;
            case 'backward':  case '后退':
                forward = editorCamera.normalizedForward;
                d = (value as number)||dist;
                forward.scale(-d,step);
                startPos.vadd(step,targetPos);
                this.startPos((t:number)=>{
                    editorCamera.pivot =this._lerpPos(startPos,targetPos,t);
                    editorCamera.SetupCamera();
                });
                break;
            case "left":case "左移":
                right = editorCamera.normalizedRight;
                d = (value as number)||dist;
                right.scale(-d,step);
                startPos.vadd(step,targetPos);
                this.startPos((t:number)=>{
                    editorCamera.pivot =this._lerpPos(startPos,targetPos,t);
                    editorCamera.SetupCamera();
                });
                break;
            case "right": case "右移":
                right = editorCamera.normalizedRight;
                d = (value as number)||dist;
                right.scale(d,step);
                startPos.vadd(step,targetPos);
                this.startPos((t:number)=>{
                    editorCamera.pivot = this._lerpPos(startPos,targetPos,t);
                    editorCamera.SetupCamera();
                });
                break;
            case "up": case "上移":
                up = editorCamera.normalizedUp;
                d = (value as number)||dist;
                up.scale(d,step);
                startPos.vadd(step,targetPos);
                this.startPos((t:number)=>{
                    editorCamera.pivot =this._lerpPos(startPos,targetPos,t);
                    editorCamera.SetupCamera();
                });
                break;
            case "down": case "下移":
                up = editorCamera.normalizedUp;
                d = (value as number)||dist;
                up.scale(-d,step);
                startPos.vadd(step,targetPos);
                this.startPos((t:number)=>{
                    editorCamera.pivot =this._lerpPos(startPos,targetPos,t);
                    editorCamera.SetupCamera();
                });
                break;
            case "rotateleft": case "左转":
                //editorCamera.rotateYaw()
                this._rotateY(camera,rotate,targetRot);
                this.startPos((t:number)=>{
                    camera.transform.rotation = editorCamera.rotation= this._lerpRot(startQuat,this._targetRot,t);
                });
                break;
            case 'rotateright': case "右转":
                this._rotateY(camera,-rotate,targetRot);
                this.startRot((t:number)=>{
                    camera.transform.rotation = editorCamera.rotation=this._lerpRot(startQuat,this._targetRot,t);
                });
                break;
            case "rotateup": case "上转":
                this._rotateX(camera,rotate,targetRot);
                this.startRot((t:number)=>{
                    camera.transform.rotation = editorCamera.rotation=editorCamera.rotation=this._lerpRot(startQuat,this._targetRot,t);
                });
                break;
            case "rotatedown": case "下转":
                this._rotateX(camera,-rotate,targetRot);
                this.startRot((t:number)=>{
                    camera.transform.rotation = editorCamera.rotation=this._lerpRot(startQuat,this._targetRot,t);
                });
                break;
            case "zoomin": case "拉近":
                this.startRot((t:number)=>{
                    camera.fieldOfView = Math.max(15,startFov-fovStep*t);
                });
                break;
            case "zoomout": case "拉远":
                this.startPos((t:number)=>{
                    camera.fieldOfView = Math.min( startFov+fovStep*t,80);
                });
                break;
            case "focus": case "聚焦":
                let node = scene.getNodeById(value as string);
                if (node)
                    (EditorEnv as any).navigationManager.focusNode(node);
                //focusNode()
                break;
            case "看天空": case 'viewsky':
                // 拉远看天空
                this._viewSkySavePos = camera.transform.position.clone();
                forward = editorCamera.normalizedForward;
                forward.y = 0;  //上下不移动
                forward.normalize();
                dist = 120;
                //forward.scale(-dist,step);
                startPos.vadd(new Vector3(0,dist,0),targetPos);
                this.startPos((t:number)=>{
                    camera.transform.position = this._lerpPos(startPos,targetPos,t);
                });

                this._rotateX(camera,60*Math.PI/180,targetRot);
                // this.startRot((t:number)=>{
                //     camera.transform.rotation = this._lerpRot(startQuat,targetRot,t);
                // });

                break;
            case 'viewsky_restore':
                // 拉远看天空
                this.startPos((t: number) => {
                    //camera.transform.position = this._lerpPos(startPos, this._viewSkySavePos, t);
                });

                this._rotateX(camera, -60 * Math.PI / 180, targetRot);
                this.startRot((t: number) => {
                    camera.transform.rotation = this._lerpRot(startQuat, targetRot, t);
                });
                break;

            case "看场景":
                // 拉远看场景
                break;
            case "orthographic":
                editorCamera.orthographic = value;
                break;
            case 'init': case '恢复摄像机':
                camera.transform.position = new Vector3(-33.032358697641584, 6.527457354588745, 1.5595578675932842);
                camera.transform.rotation = new Quaternion(-0.05195497745693936, 0.11555077252800745, -0.006052318065783488, -0.991923418783715);
                break;
        }

    }
    posTo(pos:Vector3, duration:number){

    }
}

let aiCamCtrl = new AICameraCtrl();


@IEditorEnv.regClass()
export class AI_CameraCtrl {
    /**
     * 摄像机缓动到某个位置
     * @param target
     * @param dir
     * @param tweenTm
     * @param tweenType
     */
    static cmd(this: IEditorEnv.IGameScene, operate: string, value: any) {
        aiCamCtrl.cmd(this, operate, value);
        // let camera = EditorEnv.d3Manager.sceneCamera._camera;
        // let pos = camera.transform.position;
        // let target = new Vector3(targetx, targety, targetz);
        // let dir = new Vector3();
        // Vector3.subtract(pos, target, dir);
        // Vector3.normalize(dir, dir);
        // Vector3.scale(dir, dist, dir);
        // Vector3.add(target, dir, target);
        // camera.transform.position = target;
        // camera.transform.lookAt(target, Vector3.Up);

        //editorCamera.setFocusPosition(target);
    }

    static getTreeData(this: IEditorEnv.IGameScene, ownerid:string, compid: string) {
        let sp3d = EditorEnv.scene.getNodeById(ownerid);
        if(!sp3d)
            return null;
        for( let i in sp3d.components){
            let curcomp = sp3d.components[i] as any;
            if(curcomp){
                let cid = (curcomp._extra as any).id
                if(cid && cid == compid){
                    if(curcomp.cfg){
                        return curcomp.cfg.toJson();
                    }
                }
            }
        }
        return null;
    }
}

